1 /* 2 Copyright: Marcelo S. N. Mancini (Hipreme|MrcSnm), 2018 - 2021 3 License: [https://creativecommons.org/licenses/by/4.0/|CC BY-4.0 License]. 4 Authors: Marcelo S. N. Mancini 5 6 Copyright Marcelo S. N. Mancini 2018 - 2021. 7 Distributed under the CC BY-4.0 License. 8 (See accompanying file LICENSE.txt or copy at 9 https://creativecommons.org/licenses/by/4.0/ 10 */ 11 module hip.error.handler; 12 import hip.console.log; 13 import hip.util.conv; 14 15 /** 16 * Base clas for documenting errors 17 */ 18 19 public class EngineErrorStack 20 { 21 public string stackName; 22 public string[] errorStack; 23 24 private this(string stackName) 25 { 26 this.stackName = stackName; 27 } 28 29 public static EngineErrorStack getNewStack(string stackName) 30 { 31 return new EngineErrorStack(stackName); 32 } 33 /** 34 * Adds an error to the stack 35 * Params: 36 * errorHeader = Error Short 37 * errorMessage = Error Long 38 */ 39 public void addError(string errorHeader, string errorMessage) 40 { 41 errorStack~= errorHeader ~ ": " ~ errorMessage; 42 } 43 44 public void showStack() 45 { 46 rawerror("ErrorStack: " ~ stackName); 47 const int len = cast(int)this.errorStack.length; 48 for(int i = 0; i < len; i++) 49 rawerror("\t" ~ errorStack[i]); 50 } 51 } 52 53 54 import core.stdc.stdlib; 55 56 version(iOS) 57 { 58 extern(C) void terminateiOSApp(int code); 59 ///iOS has a special terminate function which ought to be called when something happens. 60 alias terminate = terminateiOSApp; 61 } 62 else 63 { 64 alias terminate = core.stdc.stdlib.exit; 65 } 66 67 /** 68 * Class Used for handling errors 69 */ 70 public static class ErrorHandler 71 { 72 __gshared 73 { 74 private bool HAS_ANY_ERROR_HAPPENNED = false; 75 private EngineErrorStack currentStack; 76 private EngineErrorStack[] stackHistory; 77 private string[] warnHistory; 78 private bool isListening = false; 79 public string LAST_ERROR = ""; 80 } 81 82 /** 83 * This function will look wether any error has happenned 84 * stackName = This will help identify where the error ocurred 85 */ 86 public static void startListeningForErrors(string stackName = "Default Error") 87 { 88 if(isListening) 89 stopListeningForErrors(); 90 HAS_ANY_ERROR_HAPPENNED = false; 91 isListening = true; 92 currentStack = EngineErrorStack.getNewStack(stackName); 93 } 94 /** 95 * Will stop listening and 96 * Returns: HAS_ANY_ERROR_HAPPENNED 97 */ 98 public static bool stopListeningForErrors() 99 { 100 if(HAS_ANY_ERROR_HAPPENNED) 101 stackHistory~= currentStack; 102 currentStack = null; 103 isListening = false; 104 return HAS_ANY_ERROR_HAPPENNED; 105 } 106 107 private static void getError(lazy string errorHeader, lazy string error) 108 { 109 if(isListening) 110 { 111 LAST_ERROR = errorHeader ~ ": \n" ~ error; 112 currentStack.addError(errorHeader, error); 113 } 114 } 115 116 117 /** 118 * This function adds to the error stack 119 * Params: 120 * errorTitle = Error Header 121 * errorMessage = Error Message 122 */ 123 public static void showErrorMessage(string errorTitle, string errorMessage, bool isFatal = false) 124 { 125 if(isFatal) 126 { 127 rawfatal(errorTitle, "\t[[", errorMessage, "]]"); 128 } 129 else 130 { 131 rawerror(errorTitle, "\t[[", errorMessage, "]]"); 132 } 133 getError(errorTitle, errorMessage); 134 } 135 public static void showWarningMessage(string warningTitle, string warningMessage) 136 { 137 rawwarn("\nWarning: " ~ warningTitle); 138 rawwarn(warningMessage); 139 warnHistory~= warningTitle~": "~warningMessage; 140 } 141 142 /** 143 * 144 * Params: 145 * expression = Expression for looking wether an error has happenned 146 * errorTitle = Error Header 147 * errorMessage = Error Message 148 * Returns: If the error happenned 149 */ 150 public static bool assertErrorMessage(bool expression, string errorTitle, string errorMessage, bool isFatal = false, 151 string file = __FILE__, size_t line =__LINE__, string mod = __MODULE__, string func = __PRETTY_FUNCTION__) 152 { 153 expression = !expression; //Negate the expression, as it must return wether error ocurred 154 if(expression) 155 { 156 version(HIPREME_DEBUG) 157 { 158 string where = "at module '"~mod~"' "~file~":"~to!string(line)~"("~func~")\n\t"; 159 } 160 else{string where="";} 161 showErrorMessage(where~errorTitle, errorMessage, isFatal); 162 } 163 return expression; 164 } 165 166 /** 167 * 168 * Params: 169 * expression = Expression for looking wether an error has happenned 170 * errorTitle = Error Header 171 * errorMessage = Error Message 172 * Returns: If the error happenned 173 */ 174 public static bool assertLazyErrorMessage(bool expression, lazy string errorTitle, lazy string errorMessage, bool isFatal = false, 175 string file = __FILE__, size_t line =__LINE__, string mod = __MODULE__, string func = __PRETTY_FUNCTION__) 176 { 177 expression = !expression; //Negate the expression, as it must return wether error ocurred 178 if(expression) 179 { 180 version(HIPREME_DEBUG) 181 { 182 string where = "at module '"~mod~"' "~file~":"~to!string(line)~"("~func~")\n\t"; 183 } 184 else{string where="";} 185 showErrorMessage(where~errorTitle, errorMessage, isFatal); 186 } 187 return expression; 188 } 189 190 /** 191 * If you're running on a loop or need to concat your failure message, prefer using assertLazyExit. 192 */ 193 public static void assertExit(bool expression, string onAssertionFailure = "Assertion Failure", 194 string file = __FILE__, size_t line = __LINE__, string mod = __MODULE__, string func = __PRETTY_FUNCTION__) 195 { 196 if(!expression) 197 { 198 cast(void)ErrorHandler.assertErrorMessage(false, "HipAssertion", onAssertionFailure, true, 199 file, line, mod, func); 200 terminate(EXIT_FAILURE); 201 } 202 } 203 204 public static void assertLazyExit(bool expression, lazy string onAssertionFailure, 205 string file = __FILE__, size_t line = __LINE__, string mod = __MODULE__, string func = __PRETTY_FUNCTION__) 206 { 207 if(!expression) 208 { 209 cast(void)ErrorHandler.assertLazyErrorMessage(false, "HipAssertion", onAssertionFailure, true, 210 file, line, mod, func); 211 terminate(EXIT_FAILURE); 212 } 213 } 214 215 static immutable(string) assertReturn(string expression)(string onAssertionFailureMessage) 216 { 217 return `if(ErrorHandler.assertErrorMessage(`~expression~`, "HipAssertion", "`~onAssertionFailureMessage~ 218 `"))return;`; 219 } 220 221 public static void showEveryError() 222 { 223 foreach(stack; stackHistory) 224 { 225 stack.showStack(); 226 } 227 } 228 }